﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;

namespace ERefCommon
{
    /// <summary>
    /// json工具类
    /// </summary>
    public static class JsonTool
    {
        /// <summary>
        /// 根据json的结点路径获取结点值
        /// </summary>
        /// <param name="jsonFilePath">json文件路径</param>
        /// <param name="tokenPath">json结点路径</param>
        /// <returns>json结点值字符串</returns>
        /// <exception cref="ArgumentNullException">参数为空异常</exception>
        /// <exception cref="FileNotFoundException">文件不存在异常</exception>
        public static string GetJsonStr(string jsonFilePath, string tokenPath)
        {
            ValidPms(jsonFilePath, tokenPath);
            FmtFilePathAndExistCheck(ref jsonFilePath);
            string sourceStr = File.ReadAllText(jsonFilePath);
            JToken tmpToken = JObject.Parse(sourceStr);
            return tmpToken.SelectToken(tokenPath).ToString();
        }
        /// <summary>
        /// 根据json的结点路径设置结点值
        /// </summary>
        /// <param name="jsonFilePath">json文件路径</param>
        /// <param name="tokenPath">json结点路径</param>
        /// <param name="tokenValue">json结点值字符串</param>
        /// <exception cref="ArgumentNullException">参数为空异常</exception>
        /// <exception cref="FileNotFoundException">文件不存在异常</exception>
        /// <exception cref="ArgumentException">变量错误异常</exception>
        public static void SetJsonStr(string jsonFilePath, string tokenPath, string tokenValue)
        {
            ValidPms(jsonFilePath, tokenPath);
            FmtFilePathAndExistCheck(ref jsonFilePath);
            string sourceStr = File.ReadAllText(jsonFilePath);
            string[] targetPathArray = tokenPath.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
            if (targetPathArray == null || targetPathArray.Length <= 0)
            {
                throw new ArgumentException("json结点路径解析错误");
            }
            JToken obj = JToken.Parse(sourceStr);
            JToken o = obj.SelectToken(tokenPath);
            JContainer jc = o.Parent;
            JProperty jp = new JProperty(targetPathArray[targetPathArray.Length - 1], tokenValue);
            JContainer jcP = jc.Parent;
            jc.Remove();
            jcP.Add(jp);
            lock ("JsonTool") 
            {
                File.WriteAllText(jsonFilePath, JsonConvert.SerializeObject(obj));
            }
        }

        /// <summary>
        /// 对象序列化为json字符串，时间格式为国际标准，空值显示
        /// </summary>
        /// <param name="obj">要序列化的对象</param>
        /// <returns>json字符串</returns>
        public static string ToJson(object obj)
        {
            return JsonConvert.SerializeObject(obj, new JsonSerializerSettings()
            {
                DateFormatString = "yyyy-MM-dd HH:mm:ss.fff",
                NullValueHandling = NullValueHandling.Include
            });
        }

        /// <summary>
        /// json字符串反序列化为泛型
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="json">json字符串</param>
        /// <returns>泛型结果</returns>
        public static T ToGeneric<T>(string json)
        {
            return JsonConvert.DeserializeObject<T>(json, new JsonSerializerSettings()
            {
                DateFormatString = "yyyy-MM-dd HH:mm:ss.fff",
                NullValueHandling = NullValueHandling.Include
            });
        }

        /// <summary>
        /// json字符串反序列化为泛型集合类，单一实体会自动转换为集合
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="json">json字符串</param>
        /// <returns>泛型集合结果</returns>
        public static List<T> ToGenericList<T>(string json)
        {
            JsonSerializerSettings serialSettings = new JsonSerializerSettings()
            {
                DateFormatString = "yyyy-MM-dd HH:mm:ss.fff",
                NullValueHandling = NullValueHandling.Include
            };
            JToken tmpToken = JToken.Parse(json);
            List<T> resList = new List<T>();
            if (tmpToken is JArray)
            {
                resList = JsonConvert.DeserializeObject<List<T>>(json, serialSettings);
            }
            else
            {
                resList.Add(JsonConvert.DeserializeObject<T>(json, serialSettings));
            }
            return resList;
        }

        /// <summary>
        /// json字符串反序列化为对象
        /// </summary>
        /// <param name="json">json字符串</param>
        /// <returns>对象结果</returns>
        public static object ToObj(string json)
        {
            return JsonConvert.DeserializeObject(json, new JsonSerializerSettings()
            {
                DateFormatString = "yyyy-MM-dd HH:mm:ss.fff",
                NullValueHandling = NullValueHandling.Include
            });
        }


        /// <summary>
        /// 验证参数
        /// </summary>
        /// <param name="jsonFilePath">json文件路径</param>
        /// <param name="tokenPath">json配置路径</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">变量为空异常</exception>
        private static void ValidPms(string jsonFilePath, string tokenPath)
        {
            if (jsonFilePath == null || string.IsNullOrEmpty(jsonFilePath))
            {
                throw new ArgumentNullException("jsonFilePath", "json文件路径不存在");
            }
            if (tokenPath == null || string.IsNullOrEmpty(tokenPath))
            {
                throw new ArgumentNullException("tokenPath", "json结点路径为空");
            }            
        }

        /// <summary>
        /// 处理文件路径为全平台兼容模式，并验证文件是否存在
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <exception cref="FileNotFoundException">文件不存在异常</exception>
        private static void FmtFilePathAndExistCheck(ref string filePath)
        {
            filePath = filePath.Replace('\\', Path.DirectorySeparatorChar);
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException("文件不存在", filePath);
            }
        }
    }
}
